/**
 * Recode the loop function (Figure 19.12) as a single process using either select or poll.
 **/
#include "apue.h"

#include <poll.h>
#include <sys/select.h>

#define BUFFSIZE 512

#if 0
void loop(int ptym, int ignoreeof)
{
  int n, nread;
  char buf[BUFFSIZE];
  int check_in = 1;
  fd_set in_set;

  for (;;) {
    FD_ZERO(&in_set);
    FD_SET(STDIN_FILENO, &in_set);
    FD_SET(ptym, &in_set);

    // 一直阻塞直到有描述符准备好
    if ((n = select(ptym + 1, &in_set, NULL, NULL, NULL)) > 0) {
      // 检查stdin
      if (FD_ISSET(STDIN_FILENO, &in_set)) {
        if ((nread = read(STDIN_FILENO, buf, BUFFSIZE)) < 0) {
          err_sys("read error from stdin");
        } else if (nread == 0) { /* EOF */
          return;
        } else { /* nread>0，有数据可写 */
          if (writen(ptym, buf, nread) != nread)
            err_sys("writen error to master pty");
        }
      }

      // 检查ptym
      if (FD_ISSET(ptym, &in_set)) {
        if ((nread = read(ptym, buf, BUFFSIZE)) <= 0) {
          return; /*  error, or EOF */
        }

        if (writen(STDOUT_FILENO, buf, nread) != nread)
          err_sys("writen error to stdout");
      }
    } else {
      err_sys("pool error");
    }
  }
}
#else
void loop(int ptym, int ignoreeof)
{
  int n, nread;
  char buf[BUFFSIZE];
  struct pollfd fds[2];
  int check_in = 1;

  fds[0].fd = STDIN_FILENO;  // stdin
  fds[0].events = POLLIN;
  fds[1].fd = ptym;  // ptym
  fds[1].events = POLLIN |POLLOUT;

  for (;;) {
    // 一直阻塞直到有描述符准备好
    if ((n = poll(fds, 2, -1)) > 0) {
      // 检查stdin
      if (fds[0].revents != 0) {  // stdin -> ptym
        if ((nread = read(STDIN_FILENO, buf, BUFFSIZE)) < 0)
          err_sys("read error from stdin");
        else if (nread == 0) {
          return;
        } else {        /* nread>0，有数据可写 */
          if (writen(ptym, buf, nread) != nread)
            err_sys("writen error to master pty");
        }
      }

      // 检查ptym
      if (fds[1].revents & POLLIN) {  // ptym -> stdout
        if ((nread = read(ptym, buf, BUFFSIZE)) <= 0)
          return; /* signal caught, error, or EOF */

        if (writen(STDOUT_FILENO, buf, nread) != nread)
          err_sys("writen error to stdout");
      }
    } else {
      err_sys("pool error");
    }
  }
}
#endif